package soot.we.android.transfomer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import soot.Body;
import soot.BodyTransformer;
import soot.MethodOrMethodContext;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.jimple.toolkits.callgraph.CHATransformer;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Targets;
import soot.tagkit.Tag;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.UnitGraph;
import soot.util.Chain;
import soot.we.android.XML.Component;
import soot.we.android.XML.Variable;
import soot.we.android.base.ApplicationBase;
import soot.we.android.base.ComponentClass;
import soot.we.android.base.Method;
import soot.we.android.log.AlarmLog;
import soot.we.android.logic.MainThread;
import soot.we.android.logic.ProcessJimpleClasses;
import soot.we.android.test.Test;

public class ComponentConstructTransformer extends soot.SceneTransformer {
	public static List<Method> eCfgList;

	@Override
	protected void internalTransform(String arg0, Map<String, String> arg1) {

		ApplicationBase application = Test.app;

		
		ArrayList<Component> aListComp = application.getComponents();
		for (Component ec : aListComp) {
			ComponentClass eClass = new ComponentClass();
			eCfgList = new ArrayList<Method>();
			String compName = ec.getComponnetName();
			eClass.setIsEntryPoint(ec.getExported());
			eClass.setCompName(compName);
			System.out.println("instrumenting ComponentClass: " + compName);
			//****start extracting CFG of Each method in certain Class*********
			ConstructClass(compName,eClass);
			//****end extracting CFG********
			eClass.setMethodList(eCfgList);
			
			MainThread.classList.add(eClass);
			
			// ************* if it is outerClass **********
			List<String> innerClassList = ProcessJimpleClasses
					.findAnonyInnerClass(compName);
			if (innerClassList.size() > 0) {
				for (String innerClass : innerClassList) {
					eClass = new ComponentClass();
					eCfgList = new ArrayList<Method>();
					eClass.setIsEntryPoint(false);
					eClass.setCompName(innerClass);
					System.out.println("instrumenting InnerClass: " + compName);
					//****start extracting CFG of Each method in inner Class*********
					ConstructClass(innerClass,eClass);
					//****end extracting CFG***************
					eClass.setMethodList(eCfgList);
					MainThread.classList.add(eClass);

				}
			}
			// *************outerClass end**************

		}
	
	}

	private void ConstructClass(String ClassName,ComponentClass eClass) {

		SootClass sootClass = Scene.v().loadClassAndSupport(ClassName);
		sootClass.setApplicationClass();
		
		eClass.setJimpleclass(sootClass);		
		
		List<Variable> tempclassVariables = new ArrayList<Variable>();
		for (SootField sf : sootClass.getFields()) {
			Variable tempVariable = new Variable(sf.getType()
					.toString(), sf.getSubSignature());
			tempclassVariables.add(tempVariable);
		}
		
		eClass.setClassVariable(tempclassVariables);
				
		List<SootMethod> methodList = sootClass.getMethods();
		for (SootMethod sm : methodList) {
			
			Body body = sm.retrieveActiveBody();
			// Instruments bytecode

			new BodyTransformer() {

				@Override
				protected void internalTransform(Body body, String arg1,
						Map<String, String> arg2) {
					// TODO Auto-generated method stub
					UnitGraph ug = ProcessJimpleClasses.getCfgFromMethod(body);

					Method eCfg = new Method(body.getMethod().getName(), ug);
					ComponentConstructTransformer.eCfgList.add(eCfg);
				}
				
			}.transform(body);
		}
	}
}
